#include <stdbool.h>
#include <st.h>
#include "log.h"
#include "ursax.h"
#include "range-lock.h"


void range_lock_init(struct RangeLock* lock)
{
	lock->coroutines[0] = NULL;
	lock->coroutines[1] = NULL;
	lock->locked_range[0][0] = -1L;
	lock->locked_range[0][1] = -1L;
	lock->locked_range[1][0] = -1L;
	lock->locked_range[1][1] = -1L;
}


static inline bool intersect(int64_t a1, int64_t a2, int64_t b1, int64_t b2)
{
	// return (a1<=b1 && b1<=a2) || (a1<=b2 && b2<=a2) || (b1<=a1 && a1 <=b2);
	return !((a2 < b1) || (b2 < a1));
}

void range_lock(struct RangeLock* lock, int index, int64_t low, int64_t high)
{
	int other = 1 - index;	// 0-->1, 1-->0
	int64_t* x = lock->locked_range[other];
	if (unlikely(x[0]>-1L && intersect(low, high, x[0], x[1])))
	{
		st_thread_t co = st_thread_self();
		LOG_DEBUG("%s range lock intersect %d %d %d %d, th(%ld)wait ", __func__, low, high, x[0], x[1], (long)co);
		lock->coroutines[index] = co;
		int ret = st_sleep(100);		// sleep forever (suspend)
		if(ret == 0){
			LOG_ERROR("wait unlock timeout and must be some error!!!");
		}
		lock->coroutines[index] = NULL;
		LOG_DEBUG("%s range lock intersect %d %d %d %d, th(%ld)wait over ", __func__, low, high, x[0], x[1], (long)co);
	}
	lock->locked_range[index][0] = low;
	lock->locked_range[index][1] = high;
}

void range_unlock(struct RangeLock* lock, int index)
{
	lock->locked_range[index][0] = -1L;
	lock->locked_range[index][1] = -1L;

	int other = 1 - index;	// 0-->1, 1-->0
	st_thread_t coo = lock->coroutines[other];
	if (unlikely(coo != NULL))
	{
		LOG_DEBUG("%s interrupt thread %ld, then sleep", __func__, coo);
		st_thread_interrupt(coo);	// interrupt coo' sleep (resume)
		st_sleep(0);				// to avoid starvation
		LOG_DEBUG("%s interrupt thread %ld, sleep over", __func__, coo);
	}
}

